1 /*
2 * Copyright (C) 2007 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.google.common.io;
18
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.base.Preconditions.checkPositionIndexes;
21
22 import com.google.common.annotations.Beta;
23
24 import java.io.Closeable;
25 import java.io.EOFException;
26 import java.io.IOException;
27 import java.io.Reader;
28 import java.io.Writer;
29 import java.nio.CharBuffer;
30 import java.util.ArrayList;
31 import java.util.List;
32
33 /**
34 * Provides utility methods for working with character streams.
35 *
36 * <p>All method parameters must be non-null unless documented otherwise.
37 *
38 * <p>Some of the methods in this class take arguments with a generic type of
39 * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of
40 * those interfaces. Similarly for {@code Appendable & Closeable} and
41 * {@link java.io.Writer}.
42 *
43 * @author Chris Nokleberg
44 * @author Bin Zhu
45 * @author Colin Decker
46 * @since 1.0
47 */
48 @Beta
49 public final class CharStreams {
50 private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes)
51
52 private CharStreams() {}
53
54 /**
55 * Copies all characters between the {@link Readable} and {@link Appendable}
56 * objects. Does not close or flush either object.
57 *
58 * @param from the object to read from
59 * @param to the object to write to
60 * @return the number of characters copied
61 * @throws IOException if an I/O error occurs
62 */
63 public static long copy(Readable from, Appendable to) throws IOException {
64 checkNotNull(from);
65 checkNotNull(to);
66 CharBuffer buf = CharBuffer.allocate(BUF_SIZE);
67 long total = 0;
68 while (from.read(buf) != -1) {
69 buf.flip();
70 to.append(buf);
71 total += buf.remaining();
72 buf.clear();
73 }
74 return total;
75 }
76
77 /**
78 * Reads all characters from a {@link Readable} object into a {@link String}.
79 * Does not close the {@code Readable}.
80 *
81 * @param r the object to read from
82 * @return a string containing all the characters
83 * @throws IOException if an I/O error occurs
84 */
85 public static String toString(Readable r) throws IOException {
86 return toStringBuilder(r).toString();
87 }
88
89 /**
90 * Reads all characters from a {@link Readable} object into a new
91 * {@link StringBuilder} instance. Does not close the {@code Readable}.
92 *
93 * @param r the object to read from
94 * @return a {@link StringBuilder} containing all the characters
95 * @throws IOException if an I/O error occurs
96 */
97 private static StringBuilder toStringBuilder(Readable r) throws IOException {
98 StringBuilder sb = new StringBuilder();
99 copy(r, sb);
100 return sb;
101 }
102
103 /**
104 * Reads all of the lines from a {@link Readable} object. The lines do
105 * not include line-termination characters, but do include other
106 * leading and trailing whitespace.
107 *
108 * <p>Does not close the {@code Readable}. If reading files or resources you
109 * should use the {@link Files#readLines} and {@link Resources#readLines}
110 * methods.
111 *
112 * @param r the object to read from
113 * @return a mutable {@link List} containing all the lines
114 * @throws IOException if an I/O error occurs
115 */
116 public static List<String> readLines(Readable r) throws IOException {
117 List<String> result = new ArrayList<String>();
118 LineReader lineReader = new LineReader(r);
119 String line;
120 while ((line = lineReader.readLine()) != null) {
121 result.add(line);
122 }
123 return result;
124 }
125
126 /**
127 * Streams lines from a {@link Readable} object, stopping when the processor
128 * returns {@code false} or all lines have been read and returning the result
129 * produced by the processor. Does not close {@code readable}. Note that this
130 * method may not fully consume the contents of {@code readable} if the
131 * processor stops processing early.
132 *
133 * @throws IOException if an I/O error occurs
134 * @since 14.0
135 */
136 public static <T> T readLines(
137 Readable readable, LineProcessor<T> processor) throws IOException {
138 checkNotNull(readable);
139 checkNotNull(processor);
140
141 LineReader lineReader = new LineReader(readable);
142 String line;
143 while ((line = lineReader.readLine()) != null) {
144 if (!processor.processLine(line)) {
145 break;
146 }
147 }
148 return processor.getResult();
149 }
150
151 /**
152 * Discards {@code n} characters of data from the reader. This method
153 * will block until the full amount has been skipped. Does not close the
154 * reader.
155 *
156 * @param reader the reader to read from
157 * @param n the number of characters to skip
158 * @throws EOFException if this stream reaches the end before skipping all
159 * the characters
160 * @throws IOException if an I/O error occurs
161 */
162 public static void skipFully(Reader reader, long n) throws IOException {
163 checkNotNull(reader);
164 while (n > 0) {
165 long amt = reader.skip(n);
166 if (amt == 0) {
167 // force a blocking read
168 if (reader.read() == -1) {
169 throw new EOFException();
170 }
171 n--;
172 } else {
173 n -= amt;
174 }
175 }
176 }
177
178 /**
179 * Returns a {@link Writer} that simply discards written chars.
180 *
181 * @since 15.0
182 */
183 public static Writer nullWriter() {
184 return NullWriter.INSTANCE;
185 }
186
187 private static final class NullWriter extends Writer {
188
189 private static final NullWriter INSTANCE = new NullWriter();
190
191 @Override
192 public void write(int c) {
193 }
194
195 @Override
196 public void write(char[] cbuf) {
197 checkNotNull(cbuf);
198 }
199
200 @Override
201 public void write(char[] cbuf, int off, int len) {
202 checkPositionIndexes(off, off + len, cbuf.length);
203 }
204
205 @Override
206 public void write(String str) {
207 checkNotNull(str);
208 }
209
210 @Override
211 public void write(String str, int off, int len) {
212 checkPositionIndexes(off, off + len, str.length());
213 }
214
215 @Override
216 public Writer append(CharSequence csq) {
217 checkNotNull(csq);
218 return this;
219 }
220
221 @Override
222 public Writer append(CharSequence csq, int start, int end) {
223 checkPositionIndexes(start, end, csq.length());
224 return this;
225 }
226
227 @Override
228 public Writer append(char c) {
229 return this;
230 }
231
232 @Override
233 public void flush() {
234 }
235
236 @Override
237 public void close() {
238 }
239
240 @Override
241 public String toString() {
242 return "CharStreams.nullWriter()";
243 }
244 }
245
246 /**
247 * Returns a Writer that sends all output to the given {@link Appendable}
248 * target. Closing the writer will close the target if it is {@link
249 * Closeable}, and flushing the writer will flush the target if it is {@link
250 * java.io.Flushable}.
251 *
252 * @param target the object to which output will be sent
253 * @return a new Writer object, unless target is a Writer, in which case the
254 * target is returned
255 */
256 public static Writer asWriter(Appendable target) {
257 if (target instanceof Writer) {
258 return (Writer) target;
259 }
260 return new AppendableWriter(target);
261 }
262
263 // TODO(user): Remove these once Input/OutputSupplier methods are removed
264
265 static Reader asReader(final Readable readable) {
266 checkNotNull(readable);
267 if (readable instanceof Reader) {
268 return (Reader) readable;
269 }
270 return new Reader() {
271 @Override
272 public int read(char[] cbuf, int off, int len) throws IOException {
273 return read(CharBuffer.wrap(cbuf, off, len));
274 }
275
276 @Override
277 public int read(CharBuffer target) throws IOException {
278 return readable.read(target);
279 }
280
281 @Override
282 public void close() throws IOException {
283 if (readable instanceof Closeable) {
284 ((Closeable) readable).close();
285 }
286 }
287 };
288 }
289 }